/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.tamagochi.logica;

import br.com.tamagochi.bean.Tamagochi;
import br.com.tamagochi.view.ViewObserve;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * Esta classe representa a logica (thread) em relação ao tempo de execução
 * @see Thread
 * @see Runnable
 *
 * @author Allan & Fabiana
 */
public class Logica extends Thread implements Runnable{

    private final int UNIDADE;
    private final int SAUDE_UND_1;
    private final int SAUDE_UND_2;
    private final int SAUDE_UND_3;
    private final Integer[] DORMIR_TEMPOS;
    private final Integer[] COMER_TEMPOS;
    private final Integer[] BRINCAR_TEMPOS;
    private final Integer[] ACOES_UNIDADE;
    
    private boolean running;
    private boolean dormir;
    private boolean comer;
    private boolean brincar;
    private final long PERIODO;
    private Tamagochi tamagochi;
    private List<ViewObserve> observadores;
    private Acao acao; 
    
    
    
    /**
     * Construtor da classe Logica, que ira agregar os valores as contantes, 
     * atraves dos arquivos de propriedades ja definidos.
     * 
     * @param propriedade 
     */
    public Logica(Properties propriedade){
        
        this.PERIODO = Long.parseLong(propriedade.getProperty("tempo"));
        this.UNIDADE = Integer.parseInt(propriedade.getProperty("unidade"));
        
        this.SAUDE_UND_1 = Integer.parseInt(propriedade.getProperty("saude.und.1")); 
        this.SAUDE_UND_2 = Integer.parseInt(propriedade.getProperty("saude.und.2"));
        this.SAUDE_UND_3 = Integer.parseInt(propriedade.getProperty("saude.und.3"));
        this.DORMIR_TEMPOS = (Integer[])propriedade.get("dormir.tempo");
        this.COMER_TEMPOS = (Integer[])propriedade.get("comer.tempo");
        this.BRINCAR_TEMPOS = (Integer[])propriedade.get("brincar.tempo");
        this.ACOES_UNIDADE = (Integer[])propriedade.get("acoes.und");
        
        this.observadores = new ArrayList<ViewObserve>();
        
        this.running = false;
        this.comer = false;
        this.dormir = false;
        this.brincar = false;
                
        notifyArrays();
       
    }
    
    /**
     * Metodo responsavel por alterar o tamagochi
     * @param tamagochi 
     */
    public void setTamagochi(Tamagochi tamagochi){
        this.tamagochi = tamagochi;
    }
    

    public void setRunning(boolean running){
        this.running = running;
    }
    

    /**
     * Metodo respodensavel por adicionar os obeservadores.
     * @param vo 
     */
    public void addViewObserver(ViewObserve vo ){
        this.observadores.add(vo);
        notifyArrays();
    }
    
    /**
     * Metodo responsavel por excluir um dado obeservador da lista de observadores.
     * 
     * @param vo
     */
    public void removeViewObserver(ViewObserve vo){
        this.observadores.remove(vo);
    }
    
    /**
     * Metodo que notifica a lista de observadores, as restrições em questão a 
     * unidades de execução.
     */
    public void notifyArrays(){
        if(this.observadores != null){
            for(ViewObserve vo : this.observadores){
                vo.notifyArray(ACOES_UNIDADE);
            }
        }
    }
    
    /**
     * Metodo que notifica aos observadores quais são especificamente as ações que 
     * estão limitadas a unidades.
     */
    public void notifyStetaOfActions(){
        if(this.observadores != null){
            for(ViewObserve vo : this.observadores){
                vo.notifyStateOfAction(!dormir, !brincar,!comer);
            }
        }
    }
    
    /**
     * Metodo que verifica o tempo corrido do jogo e o tempo de vida do tamagochi,
     * ele ainda é responsavel por analisar a diferença entre o tempo inicial do jogo e 
     * os periodos de tempo em que ele mudara.
     * 
     * @see System.currentTimeMillis();
     * 
     * @exception InterruptedException
     */
    @Override
    public void run() {
        this.running = true;
        
        long tempoInicial = 0;
        long diferenca = 0;
        
        tempoInicial = System.currentTimeMillis();
        
        while(this.running){
            
            //atualiza o tempo de vida do bicho virtua.
            tamagochi.addTempoDeVida(diferenca);
            
            //decrementa o sono, fome e a felicidade.
            tamagochi.atualizaValores(UNIDADE);
            
            //reculpera o esta do de nivel critico.
            int nc = tamagochi.getNivelCritico();
            
            //associa o estado de nivel critico a nivel em que 
            //a saúde deve ser decrementada.
            switch(nc){
                case 1:{
                    tamagochi.atualizaSaude(-SAUDE_UND_1);
                    break;
                }
                case 2:{
                    tamagochi.atualizaSaude(-SAUDE_UND_2);
                    break;
                }
                case 3:{
                    tamagochi.atualizaSaude(-SAUDE_UND_3);
                    break;
                }
            }
            
            int no = tamagochi.getNivelOtimo(); 
            
            switch(no){
                case 1: {
                    tamagochi.atualizaSaude(SAUDE_UND_1);
                    break;
                }
                case 2:{
                    tamagochi.atualizaSaude(SAUDE_UND_2);
                    break;
                }
                case 3:{
                    tamagochi.atualizaSaude(SAUDE_UND_3);
                    break;
                }
            }
            
            try {
                sleep(PERIODO);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            
            //calcula a diferença para  a idade do tamagochi;
            diferenca = System.currentTimeMillis() - tempoInicial;
            
            tempoInicial = System.currentTimeMillis();
        }
    }
    
    /**
     * Metodo encarregado pela logica no tempo de execução, que avalia a delimitação 
     * das unidades para a ação dormir do bicho vitual
     * 
     * @param index 
     */
    public void dormir(int index){
        long tempo = (DORMIR_TEMPOS[index] / ACOES_UNIDADE[index]);
        if(this.acao != null){
            if(this.acao.isAlive()){
                this.acao.setRunning(false);
                this.acao = new Acao(new Dormir(tamagochi,UNIDADE),tempo,ACOES_UNIDADE[index]);
                this.acao.setDaemon(true);
                this.acao.setPriority(Thread.MAX_PRIORITY);
                this.acao.start();
            }else{
                this.acao = new Acao(new Dormir(tamagochi,UNIDADE),tempo,ACOES_UNIDADE[index]);
                this.acao.setDaemon(true);
                this.acao.setPriority(Thread.MAX_PRIORITY);
                this.acao.start();
            }
        }else{
            this.acao = new Acao(new Dormir(tamagochi,UNIDADE),tempo,ACOES_UNIDADE[index]);
            this.acao.setDaemon(true);
            this.acao.setPriority(Thread.MAX_PRIORITY);
            this.acao.start();
        }
    }
    
    /**
     * Metodo encarregado pela logica no tempo de execução, que avalia a delimitação 
     * das unidades para a ação Comer do bicho vitual
     * 
     * @param index 
     */
    public void comer(int index){
        long tempo = (COMER_TEMPOS[index] / ACOES_UNIDADE[index]);
        if(this.acao != null){
            if(this.acao.isAlive()){
                this.acao.setRunning(false);
                this.acao = new Acao(new Comer(tamagochi,UNIDADE),tempo,ACOES_UNIDADE[index]);
                this.acao.setDaemon(true);
                this.acao.setPriority(Thread.MAX_PRIORITY);
                this.acao.start();
            }else{
                this.acao = new Acao(new Comer(tamagochi,UNIDADE),tempo,ACOES_UNIDADE[index]);
                this.acao.setDaemon(true);
                this.acao.setPriority(Thread.MAX_PRIORITY);
                this.acao.start();
            }
        }else{
            this.acao = new Acao(new Comer(tamagochi,UNIDADE),tempo,ACOES_UNIDADE[index]);
            this.acao.setDaemon(true);
            this.acao.setPriority(Thread.MAX_PRIORITY);
            this.acao.start();
        }
    }
    
    public void brincar (int index){
        long tempo = (BRINCAR_TEMPOS[index] / ACOES_UNIDADE[index]);
        if(this.acao != null){
            if(this.acao.isAlive()){
                this.acao.setRunning(false);
                this.acao = new Acao(new Brincar(tamagochi,UNIDADE),tempo,ACOES_UNIDADE[index]);
                this.acao.setDaemon(true);
                this.acao.setPriority(Thread.MAX_PRIORITY);
                this.acao.start();
            }else{
                this.acao = new Acao(new Brincar(tamagochi,UNIDADE),tempo,ACOES_UNIDADE[index]);
                this.acao.setDaemon(true);
                this.acao.setPriority(Thread.MAX_PRIORITY);
                this.acao.start();
            }
        }else{
            this.acao = new Acao(new Brincar(tamagochi,UNIDADE),tempo,ACOES_UNIDADE[index]);
            this.acao.setDaemon(true);
            this.acao.setPriority(Thread.MAX_PRIORITY);
            this.acao.start();
        }
    }
    
    public void brincarLeft(){
        this.tamagochi.brincarLeft();
    }
    
    public void brincarRight(){
        this.tamagochi.brincarRight();
    }
    
    public Properties getTamagochiPropeties(){
        return this.tamagochi.getPropriedades();
    }
    
}
